package org.heart.springsecurity.config;


import jakarta.annotation.Resource;
import org.heart.springsecurity.JwtToken.JwtTokenFilter;
import org.heart.springsecurity.JwtToken.TokenPresenceFilter;
import org.heart.springsecurity.customAuthenticationProvider.CustomAuthenticationProvider;
import org.heart.springsecurity.mapper.AuthenticationMapper;
import org.heart.springsecurity.springSecurity.AuthenticationUserDetailsService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
@EnableMethodSecurity//开启注解方法认证（需要注意的是在requestMatchers中配置了访问权限，注解类的校验会失效requestMatchers配置优先级别高）
public class SpringSecurityConfig {


    @Resource
    private AuthenticationMapper authenticationMapper;
    @Resource
    CustomAccessDeniedHandler customAccessDeniedHandler;
    @Resource
    CustomAuthenticationProvider customAuthenticationProvider;
    @Resource
    private RedisTemplate<Object, Object> redisTemplate;


    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .csrf(AbstractHttpConfigurer::disable)
                .authorizeHttpRequests((authorize) -> authorize
                        .requestMatchers("/auth/login").permitAll() // 允许所有人访问登录接口
                        .requestMatchers("/api/v1/user/getUser").hasAnyRole("SUPER_ADMINISTRATOR", "ADMINISTRATORS") // 超级管理员和管理员可以访问获取用户信息接口
                        .requestMatchers("/api/v1/user/addUser").hasRole("SUPER_ADMINISTRATOR") // 只有超级管理员可以添加用户
                        .requestMatchers("/api/v1/user/**").hasRole("ADMINISTRATORS") // 管理员可以访问其他用户相关接口
                        .requestMatchers("/auth/refreshToken").hasAnyRole("ORDINARY_USERS", "SUPER_ADMINISTRATOR", "ADMINISTRATORS")
                        .anyRequest().hasRole("ORDINARY_USERS") // 所有其他请求至少需要 USER 角色
                )
                .exceptionHandling(exceptionHandling -> exceptionHandling
                        .accessDeniedHandler(customAccessDeniedHandler)

                )
                //过滤器是个很好的模式，可以自定义过滤器，比如token过期，token不存在等非常强大
                .addFilterBefore(new TokenPresenceFilter(), UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(new JwtTokenFilter(redisTemplate), UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }

    //自定义认证管理器
    @Bean
    public AuthenticationManager authenticationManager() {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setUserDetailsService(new AuthenticationUserDetailsService(authenticationMapper));
        authenticationProvider.setPasswordEncoder(this.passwordEncoder());
        //自定义/默认密码验证
        return new ProviderManager(customAuthenticationProvider, authenticationProvider);
    }


    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }
}
